<template>
  <div
    ref="messageContainer"
    class="text-black w-full h-full overflow-y-auto p-4 space-y-4 message-container"
  >
    <div
      v-for="message in messages"
      :key="message.id"
      class="mb-4 flex"
      :class="message.type === 'question' ? 'justify-end' : 'justify-start'"
    >
      <div
        class="flex flex-col"
        :class="
          message.type === 'question'
            ? 'max-w-[70%]'
            : 'max-w-[85%] sm:max-w-[75%] md:max-w-[80%] lg:max-w-[85%] xl:max-w-[90%]'
        "
      >
        <div
          class="text-xs text-gray-500 mb-1"
          :class="message.type === 'question' ? 'text-right' : 'text-left'"
        >
          {{ dayjs(message.createAt).format('HH:mm') }}
        </div>
        <div
          :class="[
            'p-3 rounded-lg break-words shadow-sm message-bubble',
            message.type === 'question' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'
          ]"
        >
          <template v-if="message.state === 'loading'">
            <Icon icon="svg-spinners:3-dots-move"></Icon>
          </template>
          <template v-else>
            <div
              v-if="message.state === 'stream'"
              ref="typingRef"
              class="typing-container flex w-full overflow-x-auto"
            >
              <VueMarkdown :source="displayedText(message)" :plugins="plugins" />
              <!-- {{ displayedText(message) }} -->
              <span class="typing-cursor"></span>
            </div>
            <div
              v-else
              class="prose prose-slate prose-headings:my-2 prose-li:my-0 prose-ul:my-1 prose-p:my-1 prose-pre:p-0"
            >
              <!-- image字段值是这样的 C:\\Users\\dhj\\AppData\\Roaming\\my-vue-app\\images\\QQ截图20250415204835.png" ，但是现在显示不出来 -->
              <div v-if="message.image" class="mb-3 relative group">
                <div
                  v-if="imageLoadingStatus[message.image] === 'loading'"
                  class="w-[240px] h-[180px] bg-gray-100 rounded-lg flex items-center justify-center"
                >
                  <div class="w-8 h-8 border-t-2 border-blue-500 rounded-full animate-spin"></div>
                </div>
                <img
                  v-else
                  :src="formatImagePath(message.image)"
                  alt="Message image"
                  class="max-w-[240px] max-h-[240px] object-contain rounded-lg shadow-md transition-all duration-300 hover:shadow-lg hover:scale-[1.02]"
                  @load="handleImageLoad(message.image, $event)"
                  @error="handleImageError"
                />
                <div
                  class="absolute inset-0 bg-gray-900 bg-opacity-0 group-hover:bg-opacity-10 rounded-lg transition-all duration-300"
                ></div>
              </div>
              <div>
                <VueMarkdown
                  :source="message.message.content"
                  :plugins="plugins"
                  v-if="message.type === 'answer'"
                />
                <span v-else>{{ message.message.content }}</span>
              </div>
            </div>
          </template>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { Icon } from '@iconify/vue/dist/iconify.js'
  import type { MessageListProps } from '../type'
  import dayjs from 'dayjs'
  import { ref, watch, nextTick, onMounted } from 'vue'
  import VueMarkdown from 'vue-markdown-render'
  import highlightjs from 'markdown-it-highlightjs'
  import markdownItAnchor from 'markdown-it-anchor'
  import markdownItToc from 'markdown-it-toc'
  import markdownItAttrs from 'markdown-it-attrs'
  const props = defineProps<{ messages: MessageListProps[] }>()
  const emits = defineEmits(['finishRender'])
  const typingRef = ref(null)
  const messageContainer = ref<HTMLDivElement>()
  const plugins = [highlightjs, markdownItAnchor, markdownItToc, markdownItAttrs]

  // 用于存储每条消息当前显示的文本长度
  const textLengths = ref<Record<number, number>>({})

  // 防抖相关变量
  let debounceTimer: any = null
  const DEBOUNCE_DELAY = 500 // 500毫秒的防抖延迟

  // 防抖函数
  const debounce = (callback: Function) => {
    if (debounceTimer) {
      clearTimeout(debounceTimer)
    }

    debounceTimer = setTimeout(() => {
      callback()
      debounceTimer = null
    }, DEBOUNCE_DELAY)
  }

  // 滚动到底部函数（添加平滑滚动效果）
  const scrollToBottom = () => {
    nextTick(() => {
      if (messageContainer.value) {
        messageContainer.value.scrollTo({
          top: messageContainer.value.scrollHeight,
          behavior: 'smooth' // 添加平滑滚动效果
        })
      }
    })
  }

  // 触发渲染完成事件（带防抖）
  const emitFinishRender = () => {
    debounce(() => {
      nextTick(() => {
        emits('finishRender')
      })
    })
  }

  // 返回应该显示的文本
  const displayedText = (message: MessageListProps) => {
    if (!textLengths.value[message.id]) {
      textLengths.value[message.id] = 0
    }
    return message.message.content.substring(0, textLengths.value[message.id])
  }

  // 监听消息变化，实现打字机效果
  watch(
    () => [...props.messages],
    (newMessages, oldMessages) => {
      // 检查是否有新消息添加
      if (newMessages.length !== oldMessages?.length) {
        scrollToBottom()
      }

      let hasFinishedMessages = false

      newMessages.forEach(message => {
        if (message.state === 'stream') {
          // 如果是流式消息，逐渐增加显示的文本长度
          const targetLength = message.message.content.length
          const currentLength = textLengths.value[message.id] || 0

          if (currentLength < targetLength) {
            // 设置一个定时器，逐字显示文本
            const timer = setInterval(() => {
              if (textLengths.value[message.id] < targetLength) {
                textLengths.value[message.id] = (textLengths.value[message.id] || 0) + 1
                // 每次更新文本后滚动到底部
                scrollToBottom()
              } else {
                clearInterval(timer)
              }
            }, 30) // 每30毫秒显示一个字符
          }
        } else if (message.state === 'finish') {
          // 如果消息已完成，直接显示全部内容
          textLengths.value[message.id] = message.message.content.length
          hasFinishedMessages = true
          scrollToBottom()
        }
      })

      // 只有当有已完成的消息时才触发事件（带防抖）
      if (hasFinishedMessages) {
        emitFinishRender()
      }
    },
    { deep: true, immediate: true }
  )

  // 组件挂载后初始滚动到底部
  onMounted(() => {
    scrollToBottom()
  })

  // 图片加载状态
  const imageLoadingStatus = ref({})

  // 格式化图片路径
  const formatImagePath = path => {
    if (!path) return ''

    // 设置图片加载状态
    if (imageLoadingStatus.value[path] === undefined) {
      imageLoadingStatus.value[path] = 'loading'
    }

    // 将反斜杠转换为正斜杠
    const normalizedPath = path.replace(/\\/g, '/')

    // 确保路径格式正确
    if (!normalizedPath.startsWith('safe-file://')) {
      return `safe-file://${normalizedPath}`
    }

    return normalizedPath
  }

  // 处理图片加载成功
  const handleImageLoad = (path, e) => {
    imageLoadingStatus.value[path] = 'loaded'
  }

  // 处理图片加载错误
  const handleImageError = e => {
    console.error('图片加载失败:', e.target.src)
    e.target.classList.add('bg-gray-100', 'border', 'border-dashed', 'border-gray-300')
    e.target.setAttribute('title', '图片加载失败')

    // 获取图片路径
    const imgSrc = e.target.src
    const path = Object.keys(imageLoadingStatus.value).find(key => formatImagePath(key) === imgSrc)
    if (path) {
      imageLoadingStatus.value[path] = 'error'
    }
  }
</script>

<style>
  /* 消息容器样式 */
  .message-container {
    scroll-behavior: smooth;
  }

  /* 消息气泡样式 */
  .message-bubble {
    transition: all 0.3s ease;
  }

  /* 打字机光标效果 */
  .typing-container {
    position: relative;
    display: block;
    width: 100%;
  }

  .typing-cursor {
    display: inline-block;
    width: 2px;
    height: 1em;
    background-color: currentColor;
    margin-left: 2px;
    animation: blink 0.7s infinite;
    vertical-align: middle;
    position: absolute;
    right: -4px;
    bottom: 0;
  }
  /* Markdown 样式优化 */
  .prose {
    font-size: 1rem;
    line-height: 1.6;
  }

  /* 标题样式 */
  .prose h1 {
    font-size: 1.8em;
    margin-top: 1.5em;
    margin-bottom: 0.8em;
    font-weight: 600;
  }

  .prose h2 {
    font-size: 1.5em;
    margin-top: 1.4em;
    margin-bottom: 0.7em;
    font-weight: 600;
  }

  .prose h3 {
    font-size: 1.3em;
    margin-top: 1.3em;
    margin-bottom: 0.6em;
    font-weight: 600;
  }

  /* 列表样式 */
  .prose ul {
    list-style-type: disc;
    padding-left: 1.5em;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
  }

  .prose ol {
    list-style-type: decimal;
    padding-left: 1.5em;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
  }

  .prose li {
    margin-bottom: 0.25em;
  }

  /* 代码块样式 */
  .prose pre {
    background-color: #f6f8fa;
    border-radius: 6px;
    padding: 1em;
    overflow-x: auto;
    margin: 0.8em 0;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.9em;
    line-height: 1.5;
  }

  .prose code {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.9em;
    padding: 0.2em 0.4em;
    background-color: rgba(175, 184, 193, 0.2);
    border-radius: 3px;
    white-space: pre-wrap;
  }

  .prose pre code {
    background-color: transparent;
    padding: 0;
    white-space: pre;
    border-radius: 0;
  }

  /* 表格样式 */
  .prose table {
    border-collapse: collapse;
    width: 100%;
    margin: 1em 0;
    overflow-x: auto;
    display: block;
  }

  .prose th,
  .prose td {
    border: 1px solid #dfe2e5;
    padding: 0.5em 1em;
    text-align: left;
  }

  .prose th {
    background-color: #f6f8fa;
    font-weight: 600;
  }

  /* 引用样式 */
  .prose blockquote {
    border-left: 4px solid #dfe2e5;
    padding-left: 1em;
    color: #6a737d;
    margin: 1em 0;
  }

  /* 水平线样式 */
  .prose hr {
    height: 1px;
    background-color: #dfe2e5;
    border: none;
    margin: 1.5em 0;
  }

  /* 数学公式样式 */
  .prose .katex-display {
    overflow-x: auto;
    overflow-y: hidden;
    padding: 0.5em 0;
  }

  /* 链接样式 */
  .prose a {
    color: #0366d6;
    text-decoration: none;
  }

  .prose a:hover {
    text-decoration: underline;
  }

  /* 图片样式 */
  .prose img {
    max-width: 100%;
    border-radius: 4px;
  }
</style>
